package com.wugh.fast.kernel.validator.validation;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.EnumUtil;
import com.alibaba.fastjson.util.TypeUtils;
import com.wugh.fast.kernel.core.enums.EnumInterface;
import com.wugh.fast.kernel.core.util.FastSpelContextBuilder;
import com.wugh.fast.kernel.core.util.SpelUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.EvaluationException;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.util.CollectionUtils;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.Collection;
import java.util.Objects;
import java.util.stream.Stream;

/**
 * 说明:
 *
 * @author wugh
 * @date 2018-12-21 13:50
 */
public class OptionValidatorImpl implements ConstraintValidator<Option, Object> {
    private String[] options;

    @Override
    public void initialize(Option constraintAnnotation) {
        if (ArrayUtil.isNotEmpty(constraintAnnotation.options())) {
            this.options = constraintAnnotation.options();
        } else if (constraintAnnotation.enumClass() != EnumInterface.class && EnumUtil.isEnum(constraintAnnotation.enumClass())) {
            EnumInterface[] enums = constraintAnnotation.enumClass().getEnumConstants();
            options = Stream.of(enums).map(EnumInterface::getCode).map(Object::toString).toArray(String[]::new);
        } else if (StringUtils.isNotBlank(constraintAnnotation.optionsExpression())) {
            SpelExpressionParser parser = SpelUtils.getExpressionParser();
            FastSpelContextBuilder builder = FastSpelContextBuilder.builder();
            EvaluationContext context = builder.useDefaultBeanResolver().build();
            Expression expression = parser.parseExpression(constraintAnnotation.optionsExpression());
            try {
                this.options = expression.getValue(context, String[].class);
            } catch (EvaluationException e) {
                throw new RuntimeException("无效选项表达式:" + constraintAnnotation.optionsExpression());
            }
        }
    }

    @Override
    public boolean isValid(Object value, ConstraintValidatorContext context) {
        if (value == null) {
            //为null,不处理,交由NotNull或NotBlank处理
            return true;
        }
        if (value instanceof Collection) {
            Collection<?> collection = (Collection<?>) value;
            if (CollectionUtils.isEmpty(collection)) {
                return true;
            }
            for (Object item : collection) {
                //遍历数组内容
                boolean result = validOpinion(item);
                if (!result) {
                    //有一个校验不通过,不允许
                    return false;
                }
            }
            return true;
        } else {
            return validOpinion(value);
        }
    }

    private boolean validOpinion(Object value) {
        if (value == null) {
            return true;
        }
        Class<?> clazz = value.getClass();
        for (String option : options) {
            if (Objects.equals(value, TypeUtils.cast(option, clazz, null))) {
                return true;
            }
        }
        return false;
    }
}
